package agent

import (
	"dmsv/common"
	"dmsv/ctgw"
	"dmsv/etc"
	"dmsv/models"
	"dmsv/ws"
	"encoding/json"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"sync"
	"time"
)

const (
	manager_signoff_url = "/seat/signauto"
)

//坐席管理 以坐席的number 为key
var gAgent sync.Map

type AnswerMethod string

const (
	ANSWER_BY_SIP  AnswerMethod = "sip"
	ANSWER_BY_PSTN AnswerMethod = "pstn"
)

type AgentStatus string

const (
	AGENT_STATUS_BUSY    AgentStatus = "busy"
	AGENT_STATUS_FREE    AgentStatus = "free"
	AGENT_STATUS_AWAY    AgentStatus = "away"
	AGENT_STATUS_ONLINE  AgentStatus = "online"
	AGENT_STATUS_OFFLINE AgentStatus = "offline"
	AGENT_STATUS_SIGNIN  AgentStatus = "signin"
	AGENT_STATUS_OFF     AgentStatus = "signoff"
)

type AgentInfo struct {
	serviceId     string
	mutex         sync.Mutex
	status        AgentStatus
	phoneStatus   AgentStatus
	createTime    time.Time
	number        string //当前接听号码
	display       string //外显号码
	companyNum    string //公司外显号码
	sipAcct       string //关联sip账号
	missCount     int    //未接次数
	accumulateMis int    //连续未接计数
	answerCount   int    //接听次数
	answerTime    int    //接听时长
	outCallCount  int    //外呼次数
	outCallValid  int    //有效外呼次数 - 接听
	outCallTime   int    //外呼时长
	freeTime      int
	offLine       bool //在线状态
	nextAnswer    time.Time
	appId         string
	wsClient      *ws.WsClient //websocket
	msgChannel    chan common.Message
	signQue       []string //签入队列
}

func isSipAcct(number string) bool {

	if len(number) == 14 || len(number) == 6 {
		//logs.Info("number[%v] is sip account ", number)
		return true
	}

	//logs.Info("number[%v] not sip account .", number)
	return false
}

func (a *AgentInfo) SetNextAnswer(second int) {
	a.nextAnswer = time.Now().Add(time.Duration(second) * time.Second)
}

func (a *AgentInfo) OutOfAnswerTime() bool {

	//整理时间已过
	return time.Now().After(a.nextAnswer)
}

func (a *AgentInfo) NextAnswerTime() string {

	//整理时间已过
	return a.nextAnswer.Format("15:04:05")
}

func (a *AgentInfo) eventProcessTask() {

	logs.Info("[%v]serviceId[%v] 消息处理任务启动...", a.appId, a.serviceId)
	go func() {
		for {

			message, ok := <-a.msgChannel
			if !ok {
				logs.Debug("appId:[%v] serviceId [%v] event channel closed", a.appId, a.serviceId)
				return
			}

			logs.Debug("[%v]serviceId[%v]收到消息:%v", a.appId, a.serviceId, message)
			switch message.Event {
			//websocket连接超时，认为坐席离线
			case common.EVT_TIMEOUT:
				logs.Info("[%v]坐席[%v]连接超时,签出处理", a.appId, a.serviceId)
				RemoveAgent(a.appId, a.number, a.serviceId)
				if a.msgChannel != nil {
					close(a.msgChannel)
					a.msgChannel = nil
					a.wsClient.RemoveMsgChan()
				}

				//发送给后端坐席管理
				a.sendSignOffMsg()
			}
		}
	}()
}

func (a *AgentInfo) sendSignOffMsg() {

	type rptSingOut struct {
		Event     string `json:"event"`
		AppId     string `json:"appId"`
		TimeStamp string `json:"timeStamp"`
		ServiceId string `json:"serviceId"`
		Data      string `json:"data"`
	}

	msg := rptSingOut{
		Event:     "serviceTimeout",
		AppId:     a.appId,
		ServiceId: a.serviceId,
		TimeStamp: time.Now().Format("2006-01-02 15:04:05"),
	}

	msgBody, err := json.Marshal(msg)
	if err != nil {
		logs.Error("json err:%v", err)
		return
	}

	ctgw.SendMessage(etc.Conf.Base.CallBack, msgBody)
}

func (a *AgentInfo) IsBlank() bool {
	return a.serviceId == ""
}

func (a *AgentInfo) Number() string {
	return a.number
}

func (a *AgentInfo) ServiceId() string {
	return a.serviceId
}

func (a *AgentInfo) MisCallPlus() int {
	a.accumulateMis++
	a.missCount++

	logs.Debug("[%v] serviceId[%v]，未接次数:%v,总未接次数:%v", a.appId, a.serviceId, a.accumulateMis, a.missCount)
	return a.accumulateMis
}

func (a *AgentInfo) MissCall() int {

	return a.accumulateMis
}

func (a *AgentInfo) Status() string {
	return string(a.status)
}

func (a *AgentInfo) PhoneStatus() string {
	return string(a.phoneStatus)
}

func (a *AgentInfo) CallTime() int {
	return a.answerTime
}

func (a *AgentInfo) AnswerCount() int {
	return a.answerCount
}

func (a *AgentInfo) FreeTime() int {

	return a.freeTime
}

func (a *AgentInfo) IsFree() bool {

	a.mutex.Lock()
	defer a.mutex.Unlock()

	if a.status == AGENT_STATUS_FREE &&
		a.phoneStatus == AGENT_STATUS_FREE {

		return true
	}

	return false
}

func (a *AgentInfo) IsBusy() bool {

	a.mutex.Lock()
	defer a.mutex.Unlock()

	if a.status != AGENT_STATUS_FREE ||
		a.phoneStatus != AGENT_STATUS_FREE {

		return true
	}

	return false
}

func (a *AgentInfo) SetBusy() {
	a.status = AGENT_STATUS_AWAY
	a.syncStatus()
}

func (a *AgentInfo) SetFree() {
	a.status = AGENT_STATUS_FREE
	a.syncStatus()
	a.MisCallReset()
}

func (a *AgentInfo) StatusInit() {
	a.status = AGENT_STATUS_FREE
	a.phoneStatus = AGENT_STATUS_FREE
}

func (a *AgentInfo) GetConfStatus() string {
	return string(a.status)
}

func (a *AgentInfo) PhoneIsFree() bool {

	return a.phoneStatus == AGENT_STATUS_FREE
}

func (a *AgentInfo) SetPhoneFree(callTime int, callin bool) {

	a.mutex.Lock()
	defer a.mutex.Unlock()
	if a.phoneStatus == AGENT_STATUS_FREE {
		return
	}

	a.phoneStatus = AGENT_STATUS_FREE

	//有通话的情况下，更新相应时长
	if callTime > 0 {
		if callin {
			a.answerCount++
			a.answerTime += callTime
		} else {
			a.outCallValid++
			a.outCallTime += callTime
		}
	}

	if false == callin {
		a.outCallCount++
	}

	logs.Debug("company[%v] service[%v] to free,通话时长:%v,接听次数:%v,接听时长:%v;外呼接听:%v,外呼次数:%v,外呼时长:%v ",
		a.appId, a.serviceId, callTime,
		a.answerCount, a.answerTime,
		a.outCallValid, a.outCallCount, a.outCallTime)

	a.syncStatus()

	return
}

func (a *AgentInfo) SetPhoneBusy() {

	if false == a.PhoneIsFree() {
		return
	}

	a.mutex.Lock()
	defer a.mutex.Unlock()

	logs.Debug("company [%v] service [%v] phone set busy", a.appId, a.serviceId)
	a.phoneStatus = AGENT_STATUS_BUSY

	a.syncStatus()

	return
}

func (a *AgentInfo) SignInSkillQue(skillId string) {

	if len(skillId) == 0 {
		logs.Error("坐席[%v]签入存储失败:坐席Id[%v] 为空.", a.serviceId, skillId)
		return
	}

	a.signQue = append(a.signQue, skillId)
	err := models.StoreSignIn(a.appId, skillId, a.number, a.serviceId, a.display)
	if err != nil {
		logs.Error("[%v] service [%v] sign in save to sql err:%v", a.appId, a.serviceId, err)
	}

}

func (a *AgentInfo) SignOutSkillQue(skillId string) bool {

	if len(skillId) > 0 {
		for index, skill := range a.signQue {
			if skillId == skill {
				a.signQue = append(a.signQue[:index], a.signQue[index+1:]...)
				break
			}
		}
	} else {
		a.signQue = make([]string, 0, 0)
	}

	//数据库中删除相关信息
	err := models.StoreSignOff(a.appId, skillId, a.serviceId)
	if err != nil {
		logs.Error("[%v]坐席签队列%v 出报错:%v。内容:%v", a.appId, skillId, skillId, err)
	}

	if len(a.signQue) == 0 {
		RemoveAgent(a.appId, a.number, a.serviceId)
		return true
	}

	return false
}

func (a *AgentInfo) GetServeNumber() string {
	if a.number == a.serviceId {
		return a.sipAcct
	}

	return a.number
}

func (a *AgentInfo) SetDsplay(display string) {

	a.display = display
}

func (a *AgentInfo) SetCompanyNumber(number string) {
	a.companyNum = number
}

func (a *AgentInfo) GetDsplay() (number string) {

	if a.display == "" {
		return a.companyNum
	}

	return a.display
}

func (a *AgentInfo) GetAppId() string {
	return a.appId
}

func (a *AgentInfo) IsLocal() bool {
	return a.serviceId == a.number
}

func NewBlankAgent() *AgentInfo {

	return &AgentInfo{
		serviceId:   "",
		status:      AGENT_STATUS_FREE,
		phoneStatus: AGENT_STATUS_FREE,
		answerCount: 9999999,
		answerTime:  9999999,
		freeTime:    -1,
	}
}

func GetAgentInfoByService(appId, serviceId string) (*AgentInfo, error) {

	a, ok := gAgent.Load(appId + serviceId)
	if ok && false == a.(*AgentInfo).offLine {
		return a.(*AgentInfo), nil
	} else {
		return nil, fmt.Errorf("no agent of %v:%v", appId, serviceId)
	}
}

func GetAgentInfo(sipUser string) (*AgentInfo, error) {

	v, ok := gAgent.Load(sipUser)
	if ok {
		return v.(*AgentInfo), nil
	} else {
		return nil, fmt.Errorf("no agent of %v", sipUser)
	}
}

//坐席关联websocket
func AddAgentWsChannel(wsClient *ws.WsClient) error {

	agent, ok := gAgent.Load(wsClient.SipAcct)
	if ok {
		agent.(*AgentInfo).wsClient = wsClient

		logs.Debug("坐席[%v]关联webclient成功:%v ", agent.(*AgentInfo).serviceId, wsClient.SipAcct)
	} else {
		agent, ok = gAgent.Load(wsClient.AppId + wsClient.ServiceId)
		if ok {
			agent.(*AgentInfo).wsClient = wsClient
			logs.Warn("websocket连接,sipAcct未关联:坐席已签入,sip账号:%v,serviceId:%v",
				wsClient.SipAcct, agent.(*AgentInfo).serviceId)
		} else {
			logs.Error("sipAcct未关联:坐席未签入,sip账号:%v,serviceId:%v", wsClient.SipAcct, wsClient.ServiceId)
			return fmt.Errorf("sipNotReg")
		}
	}

	//建立消息通道 websocket 和坐席之间
	msgChannel := make(chan common.Message, 10)
	//logs.Debug("[%v]坐席[%v]初始化channel:%v", agent.(*AgentInfo).appId, agent.(*AgentInfo).serviceId, msgChannel)
	agent.(*AgentInfo).msgChannel = msgChannel
	agent.(*AgentInfo).eventProcessTask()
	wsClient.BindMsgChan(msgChannel)

	return nil
}

func DetectSipReg(sipAcct string) error {

	if false == common.DetectNumberIsSipAcct(sipAcct) {
		return nil
	}

	_, ok := gAgent.Load(sipAcct)
	if !ok {
		return fmt.Errorf("sipNotReg")
	}

	return nil
}

func NewAgent(appId, number, id, display string) (agent *AgentInfo, err error) {

	value, ok := gAgent.Load(appId + id)
	if ok && time.Since(value.(*AgentInfo).createTime) < 8*time.Hour {

		agent = value.(*AgentInfo)
		agent.offLine = false
		agent.createTime = time.Now()
		agent.MisCallReset()
		agent.status = AGENT_STATUS_FREE
		agent.phoneStatus = AGENT_STATUS_FREE
		agent.number = number
		agent.companyNum = display

	} else {

		agent = &AgentInfo{
			appId:       appId,
			serviceId:   id,
			status:      AGENT_STATUS_FREE,
			phoneStatus: AGENT_STATUS_FREE,
			number:      number,
			companyNum:  display,
			signQue:     make([]string, 0, 0),
			offLine:     true,
			createTime:  time.Now(),
		}
		gAgent.Store(appId+id, agent)
	}

	//sip账号为key
	if isSipAcct(number) {
		if old, ok := gAgent.Load(number); ok {
			return nil, fmt.Errorf("sipAcct:%v 已被坐席[%v]使用", number, old.(*AgentInfo).serviceId)
		}
		gAgent.Store(number, agent)
	}

	return agent, nil
}

func RemoveAgent(appId, number, id string) {

	agent, ok := gAgent.Load(appId + id)
	if ok {
		agent.(*AgentInfo).offLine = true
	}

	if isSipAcct(number) {
		logs.Debug("[%v]坐席Id[%v]删除对应分机号[%v]", appId, id, number)
		gAgent.Delete(number)
	}
}

func (a *AgentInfo) Reset() {
	a.freeTime = 0
	a.answerCount = 0
	a.answerTime = 0
	a.outCallValid = 0
	a.outCallTime = 0
	a.outCallCount = 0
	a.missCount = 0
	a.accumulateMis = 0
}

func (a *AgentInfo) MisCallReset() {

	a.accumulateMis = 0
	logs.Debug("[%v] 重置坐席[%v]计数次数为0 ", a.appId, a.serviceId)
}

type jsonData struct {
	ServiceId   string      `json:"service_id"`
	Status      AgentStatus `json:"status"`
	PhoneStatus AgentStatus `json:"phone_status"`
	AnswerCount int         `json:"answer_count"` //接听次数
	CallTime    int         `json:"call_time"`    //通话时长
	FreeTime    int         `json:"free_time"`    //空闲时长
	LastUpdate  time.Time   `json:"last_update"`
}

func (a *AgentInfo) UpdataStatus(data string) {

	newStatus := &jsonData{}

	err := json.Unmarshal([]byte(data), newStatus)
	if err != nil {
		logs.Error("json err:%v from:%v", err, data)
		return
	}

	if a.serviceId != newStatus.ServiceId {
		logs.Error("service Id is not match:%v->%v", a.serviceId, data)
		return
	}

	a.status = newStatus.Status
	a.phoneStatus = newStatus.PhoneStatus

	if a.answerCount > newStatus.AnswerCount {
		logs.Error("接听次数数据错误:redis:%v;local:%v ", newStatus.AnswerCount, a.answerCount)
	}

	if a.answerTime > newStatus.CallTime {
		logs.Error("接听时长数据错误:redis:%v;local:%v ", newStatus.CallTime, a.answerTime)
	}

	a.answerCount = newStatus.AnswerCount
	a.freeTime = newStatus.FreeTime
	a.answerTime = newStatus.CallTime

	return
}

func (a *AgentInfo) syncStatus() {

	info := jsonData{
		ServiceId:   a.serviceId,
		Status:      a.status,
		PhoneStatus: a.phoneStatus,
		AnswerCount: a.answerCount,
		CallTime:    a.answerTime,
		FreeTime:    a.freeTime,
		LastUpdate:  time.Now(),
	}

	res, err := json.Marshal(info)
	if err != nil {
		logs.Error("service %v update status json err:%v", a.serviceId, err)
	}

	synToRedis(a.appId, a.serviceId, string(res))
}

func (a *AgentInfo) WsSendNewCall(callId, caller, callee, callType string) {

	if a.wsClient != nil {
		logs.Debug("[%v]发送websocket 呼入事件;caller:%v,callee:%v", callId, caller, callee)
		a.wsClient.SendNewCallRpt(callId, caller, callee, callType)
	} else {
		logs.Error("[%v] 坐席 [%v] 失去连接，无法发送 呼入事件", callId, a.ServiceId())
	}
}

func (a *AgentInfo) WsSendSetBusy() {

	if a.wsClient != nil {
		logs.Debug("[%v][%v]发送websocket 示忙", a.appId, a.serviceId)
		a.wsClient.SendSetBusy()
	} else {
		logs.Error("[%v] 坐席 [%v] 失去连接，无法发送 示忙事件", a.ServiceId())
	}
}

func (a *AgentInfo) WsStatusChange() {

	if a.wsClient != nil {
		logs.Debug("[%v][%v]发送websocket 示忙", a.appId, a.serviceId)
		a.wsClient.StatusChange()
	} else {
		logs.Error("[%v] 坐席 [%v] 失去连接，无法发送 示忙事件", a.appId, a.ServiceId())
	}
}

func UpdateAgentAnswerNumber(companyId, serviceId, number string) {

	a, ok := gAgent.Load(companyId + serviceId)
	if ok {
		agent := a.(*AgentInfo)
		agent.number = number
	}
}
